using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using HslCommunication.BasicFramework;

namespace HslCommunication.MQTT
{
	/// <summary>
	/// Mqtt协议的辅助类，提供了一些协议相关的基础方法，方便客户端和服务器端一起调用。<br />
	/// The auxiliary class of the Mqtt protocol provides some protocol-related basic methods for the client and server to call together.
	/// </summary>
	public class MqttHelper
	{
		/// <summary>
		/// 根据数据的总长度，计算出剩余的数据长度信息<br />
		/// According to the total length of the data, calculate the remaining data length information
		/// </summary>
		/// <param name="length">数据的总长度</param>
		/// <returns>计算结果</returns>
		public static OperateResult<byte[]> CalculateLengthToMqttLength(int length)
		{
			if (length > 268435455)
			{
				return new OperateResult<byte[]>(StringResources.Language.MQTTDataTooLong);
			}
			if (length < 128)
			{
				return OperateResult.CreateSuccessResult(new byte[1]
				{
					(byte)length
				});
			}
			if (length < 16384)
			{
				return OperateResult.CreateSuccessResult(new byte[2]
				{
					(byte)(length % 128 + 128),
					(byte)(length / 128)
				});
			}
			if (length < 2097152)
			{
				return OperateResult.CreateSuccessResult(new byte[3]
				{
					(byte)(length % 128 + 128),
					(byte)(length / 128 % 128 + 128),
					(byte)(length / 128 / 128)
				});
			}
			return OperateResult.CreateSuccessResult(new byte[4]
			{
				(byte)(length % 128 + 128),
				(byte)(length / 128 % 128 + 128),
				(byte)(length / 128 / 128 % 128 + 128),
				(byte)(length / 128 / 128 / 128)
			});
		}

		/// <summary>
		/// 将一个数据打包成一个mqtt协议的内容<br />
		/// Pack a piece of data into a mqtt protocol
		/// </summary>
		/// <param name="control">控制码</param>
		/// <param name="flags">标记</param>
		/// <param name="variableHeader">可变头的字节内容</param>
		/// <param name="payLoad">负载数据</param>
		/// <returns>带有是否成功的结果对象</returns>
		public static OperateResult<byte[]> BuildMqttCommand(byte control, byte flags, byte[] variableHeader, byte[] payLoad)
		{
			if (variableHeader == null)
			{
				variableHeader = new byte[0];
			}
			if (payLoad == null)
			{
				payLoad = new byte[0];
			}
			control = (byte)(control << 4);
			byte value = (byte)(control | flags);
			OperateResult<byte[]> operateResult = CalculateLengthToMqttLength(variableHeader.Length + payLoad.Length);
			if (!operateResult.IsSuccess)
			{
				return operateResult;
			}
			MemoryStream memoryStream = new MemoryStream();
			memoryStream.WriteByte(value);
			memoryStream.Write(operateResult.Content, 0, operateResult.Content.Length);
			if (variableHeader.Length != 0)
			{
				memoryStream.Write(variableHeader, 0, variableHeader.Length);
			}
			if (payLoad.Length != 0)
			{
				memoryStream.Write(payLoad, 0, payLoad.Length);
			}
			byte[] value2 = memoryStream.ToArray();
			memoryStream.Dispose();
			return OperateResult.CreateSuccessResult(value2);
		}

		/// <summary>
		/// 将字符串打包成utf8编码，并且带有2个字节的表示长度的信息<br />
		/// Pack the string into utf8 encoding, and with 2 bytes of length information
		/// </summary>
		/// <param name="message">文本消息</param>
		/// <returns>打包之后的信息</returns>
		public static byte[] BuildSegCommandByString(string message)
		{
			byte[] array = string.IsNullOrEmpty(message) ? new byte[0] : Encoding.UTF8.GetBytes(message);
			byte[] array2 = new byte[array.Length + 2];
			array.CopyTo(array2, 2);
			array2[0] = (byte)(array.Length / 256);
			array2[1] = (byte)(array.Length % 256);
			return array2;
		}

		/// <summary>
		/// 从MQTT的缓存信息里，提取文本信息<br />
		/// Extract text information from MQTT cache information
		/// </summary>
		/// <param name="buffer">Mqtt的报文</param>
		/// <param name="index">索引</param>
		/// <returns>值</returns>
		public static string ExtraMsgFromBytes(byte[] buffer, ref int index)
		{
			int num = index;
			int num2 = buffer[index] * 256 + buffer[index + 1];
			index = index + 2 + num2;
			return Encoding.UTF8.GetString(buffer, num + 2, num2);
		}

		/// <summary>
		/// 从MQTT的缓存信息里，提取长度信息<br />
		/// Extract length information from MQTT cache information
		/// </summary>
		/// <param name="buffer">Mqtt的报文</param>
		/// <param name="index">索引</param>
		/// <returns>值</returns>
		public static int ExtraIntFromBytes(byte[] buffer, ref int index)
		{
			int result = buffer[index] * 256 + buffer[index + 1];
			index += 2;
			return result;
		}

		/// <summary>
		/// 从MQTT的缓存信息里，提取长度信息<br />
		/// Extract length information from MQTT cache information
		/// </summary>
		/// <param name="data">数据信息</param>
		/// <returns>值</returns>
		public static byte[] BuildIntBytes(int data)
		{
			return new byte[2]
			{
				BitConverter.GetBytes(data)[1],
				BitConverter.GetBytes(data)[0]
			};
		}

		/// <summary>
		/// 创建MQTT连接服务器的报文信息<br />
		/// Create MQTT connection server message information
		/// </summary>
		/// <param name="connectionOptions">连接配置</param>
		/// <param name="protocol">协议的内容</param>
		/// <returns>返回是否成功的信息</returns>
		public static OperateResult<byte[]> BuildConnectMqttCommand(MqttConnectionOptions connectionOptions, string protocol = "MQTT")
		{
			List<byte> list = new List<byte>();
			list.AddRange(new byte[2]
			{
				0,
				4
			});
			list.AddRange(Encoding.ASCII.GetBytes(protocol));
			list.Add(4);
			byte b = 0;
			if (connectionOptions.Credentials != null)
			{
				b = (byte)(b | 0x80u);
				b = (byte)(b | 0x40u);
			}
			if (connectionOptions.CleanSession)
			{
				b = (byte)(b | 2u);
			}
			list.Add(b);
			if (connectionOptions.KeepAlivePeriod.TotalSeconds < 1.0)
			{
				connectionOptions.KeepAlivePeriod = TimeSpan.FromSeconds(1.0);
			}
			byte[] bytes = BitConverter.GetBytes((int)connectionOptions.KeepAlivePeriod.TotalSeconds);
			list.Add(bytes[1]);
			list.Add(bytes[0]);
			List<byte> list2 = new List<byte>();
			list2.AddRange(BuildSegCommandByString(connectionOptions.ClientId));
			if (connectionOptions.Credentials != null)
			{
				list2.AddRange(BuildSegCommandByString(connectionOptions.Credentials.UserName));
				list2.AddRange(BuildSegCommandByString(connectionOptions.Credentials.Password));
			}
			return BuildMqttCommand(1, 0, list.ToArray(), list2.ToArray());
		}

		/// <summary>
		/// 根据服务器返回的信息判断当前的连接是否是可用的<br />
		/// According to the information returned by the server to determine whether the current connection is available
		/// </summary>
		/// <param name="code">功能码</param>
		/// <param name="data">数据内容</param>
		/// <returns>是否可用的连接</returns>
		public static OperateResult CheckConnectBack(byte code, byte[] data)
		{
			if (code >> 4 != 2)
			{
				return new OperateResult("MQTT Connection Back Is Wrong: " + code);
			}
			if (data.Length < 2)
			{
				return new OperateResult("MQTT Connection Data Is Short: " + SoftBasic.ByteToHexString(data, ' '));
			}
			int num = data[1];
			int num2 = data[0];
			if (num > 0)
			{
				return new OperateResult(num, GetMqttCodeText(num));
			}
			return OperateResult.CreateSuccessResult();
		}

		/// <summary>
		/// 获取当前的错误的描述信息<br />
		/// Get a description of the current error
		/// </summary>
		/// <param name="status">状态信息</param>
		/// <returns>描述信息</returns>
		public static string GetMqttCodeText(int status)
		{
			return status switch
			{
				1 => StringResources.Language.MQTTStatus01, 
				2 => StringResources.Language.MQTTStatus02, 
				3 => StringResources.Language.MQTTStatus03, 
				4 => StringResources.Language.MQTTStatus04, 
				5 => StringResources.Language.MQTTStatus05, 
				_ => StringResources.Language.UnknownError, 
			};
		}

		/// <summary>
		/// 创建Mqtt发送消息的命令<br />
		/// Create Mqtt command to send messages
		/// </summary>
		/// <param name="message">封装后的消息内容</param>
		/// <returns>结果内容</returns>
		public static OperateResult<byte[]> BuildPublishMqttCommand(MqttPublishMessage message)
		{
			byte b = 0;
			if (!message.IsSendFirstTime)
			{
				b = (byte)(b | 8u);
			}
			if (message.Message.Retain)
			{
				b = (byte)(b | 1u);
			}
			if (message.Message.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtLeastOnce)
			{
				b = (byte)(b | 2u);
			}
			else if (message.Message.QualityOfServiceLevel == MqttQualityOfServiceLevel.ExactlyOnce)
			{
				b = (byte)(b | 4u);
			}
			else if (message.Message.QualityOfServiceLevel == MqttQualityOfServiceLevel.OnlyTransfer)
			{
				b = (byte)(b | 6u);
			}
			List<byte> list = new List<byte>();
			list.AddRange(BuildSegCommandByString(message.Message.Topic));
			if (message.Message.QualityOfServiceLevel != 0)
			{
				list.Add(BitConverter.GetBytes(message.Identifier)[1]);
				list.Add(BitConverter.GetBytes(message.Identifier)[0]);
			}
			return BuildMqttCommand(3, b, list.ToArray(), message.Message.Payload);
		}

		/// <summary>
		/// 创建Mqtt发送消息的命令<br />
		/// Create Mqtt command to send messages
		/// </summary>
		/// <param name="topic">主题消息内容</param>
		/// <param name="payload">数据负载</param>
		/// <returns>结果内容</returns>
		public static OperateResult<byte[]> BuildPublishMqttCommand(string topic, byte[] payload)
		{
			return BuildMqttCommand(3, 0, BuildSegCommandByString(topic), payload);
		}

		/// <summary>
		/// 创建Mqtt订阅消息的命令<br />
		/// Command to create Mqtt subscription message
		/// </summary>
		/// <param name="message">订阅的主题</param>
		/// <returns>结果内容</returns>
		public static OperateResult<byte[]> BuildSubscribeMqttCommand(MqttSubscribeMessage message)
		{
			List<byte> list = new List<byte>();
			List<byte> list2 = new List<byte>();
			list.Add(BitConverter.GetBytes(message.Identifier)[1]);
			list.Add(BitConverter.GetBytes(message.Identifier)[0]);
			for (int i = 0; i < message.Topics.Length; i++)
			{
				list2.AddRange(BuildSegCommandByString(message.Topics[i]));
				if (message.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtMostOnce)
				{
					list2.AddRange(new byte[1]);
				}
				else if (message.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtLeastOnce)
				{
					list2.AddRange(new byte[1]
					{
						1
					});
				}
				else
				{
					list2.AddRange(new byte[1]
					{
						2
					});
				}
			}
			return BuildMqttCommand(8, 2, list.ToArray(), list2.ToArray());
		}

		/// <summary>
		/// 创建Mqtt取消订阅消息的命令<br />
		/// Create Mqtt unsubscribe message command
		/// </summary>
		/// <param name="message">订阅的主题</param>
		/// <returns>结果内容</returns>
		public static OperateResult<byte[]> BuildUnSubscribeMqttCommand(MqttSubscribeMessage message)
		{
			List<byte> list = new List<byte>();
			List<byte> list2 = new List<byte>();
			list.Add(BitConverter.GetBytes(message.Identifier)[1]);
			list.Add(BitConverter.GetBytes(message.Identifier)[0]);
			for (int i = 0; i < message.Topics.Length; i++)
			{
				list2.AddRange(BuildSegCommandByString(message.Topics[i]));
			}
			return BuildMqttCommand(10, 2, list.ToArray(), list2.ToArray());
		}

		/// <summary>
		/// 解析从MQTT接受的客户端信息，解析成实际的Topic数据及Payload数据<br />
		/// Parse the client information received from MQTT and parse it into actual Topic data and Payload data
		/// </summary>
		/// <param name="mqttCode">MQTT的命令码</param>
		/// <param name="data">接收的MQTT原始的消息内容</param>
		/// <returns>解析的数据结果信息</returns>
		public static OperateResult<string, byte[]> ExtraMqttReceiveData(byte mqttCode, byte[] data)
		{
			if (data.Length < 2)
			{
				return new OperateResult<string, byte[]>(StringResources.Language.ReceiveDataLengthTooShort + data.Length);
			}
			int num = data[0] * 256 + data[1];
			if (data.Length < 2 + num)
			{
				return new OperateResult<string, byte[]>($"Code[{mqttCode:X2}] Subscribe Error: {SoftBasic.ByteToHexString(data, ' ')}");
			}
			string value = (num > 0) ? Encoding.UTF8.GetString(data, 2, num) : string.Empty;
			byte[] array = new byte[data.Length - num - 2];
			Array.Copy(data, num + 2, array, 0, array.Length);
			return OperateResult.CreateSuccessResult(value, array);
		}
	}
}
